﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace SO.SharePoint.Utilities.Logging
{
    public enum FilterableLogFields
    {
        Category, 
        Correlation,
        Level
    }
    
    public class LogReader
    {
        private string _filename;
        private List<LogEntry> _entries;
        private List<LogEntry> _filteredEntries;

        public LogReader(string filename)
        {
            _filename = filename;
            _entries = new List<LogEntry>();
        }

        public List<LogEntry> Entries
        {
            get { return _entries; }
        }

        public List<LogEntry> FilterResult
        {
            get { return _filteredEntries; }
        }

        public void Filter(FilterableLogFields field, string filter)
        {
            switch (field)
            {
                case FilterableLogFields.Category:
                    FilterByCategory(filter);
                    break;

                case FilterableLogFields.Correlation:
                    FilterByCorrelation(filter);
                    break;

                case FilterableLogFields.Level:
                    FilterByLevel(filter);
                    break;
            }
        }

        private void FilterByCategory(string category)
        {
            _filteredEntries = _entries.FindAll(
                delegate(LogEntry entry)
                {
                    return entry.Category.ToUpper() == category.ToUpper();
                }
            );
        }

        private void FilterByCorrelation(string correlation)
        {
            _filteredEntries = _entries.FindAll(
                delegate(LogEntry entry)
                {
                    return entry.Correlation.Contains(correlation);
                }
            );
        }

        private void FilterByLevel(string level)
        {
            _filteredEntries = _entries.FindAll(
                delegate(LogEntry entry)
                {
                    return entry.Level.ToUpper() == level.ToUpper();
                }
            );
        }

        public void Parse()
        {
            try
            {
                _entries.Clear();

                Stream stream = new FileStream(_filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

                StreamReader reader = new StreamReader(stream);
                string line;
                LogEntry entry;
                bool isFirstLine = true;
                int index = 0;

                while (!reader.EndOfStream)
                {
                    line = reader.ReadLine();
                    if (!isFirstLine)
                    {
                        entry = ParseLine(line);
                        entry.Index = index;
                        _entries.Add(entry);

                        index++;
                    }
                    else
                    {
                        isFirstLine = false;
                    }
                }

                reader.Close();
            }
            catch (Exception ex)
            {

            }
        }

        private LogEntry ParseLine(string line)
        {
            try
            {
                string[] parts = line.Split('\t');
                LogEntry log = new LogEntry();

                if ((parts.Length == 8) || (parts.Length == 9))
                {
                    log.TimeStamp = DateTime.Parse(parts[0].TrimEnd());
                    log.Process = parts[1].TrimEnd();
                    log.Tid = parts[2].TrimEnd();
                    log.Area = parts[3].TrimEnd();
                    log.Category = parts[4].TrimEnd();
                    log.EventId = parts[5].TrimEnd();
                    log.Level = parts[6].TrimEnd();
                    log.Message = parts[7].TrimEnd();
                    if (parts.Length == 9)
                        log.Correlation = parts[8].TrimEnd();

                    return log;
                }
                else
                {
                    throw new ArgumentException("Invalid ULS log file line");
                }
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("Error parsing line'{0}', line", ex));
            }
        }
    }
}
